/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Traffic;

import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author Matthew
 */
public class Model
{
    private Zones zones;
    private VehicleController v;
    private TrafficLightController tl;
    
    Random r;

    Model()
    {
        //Initialise Variables
        zones = new Zones();
        v = new VehicleController(zones);
        r = new Random();
        tl = new TrafficLightController(zones);

        //Setup the Model
        setupRoads();
    }

    public void runCycle()
    {
        v.runCycle();
        tl.tick();
        Settings.cyclesRun++;
    }

    public ArrayList<Vehicle> getVehicleList()
    {
        return v.vehicles;
    }

    private void createSpawns(PositionArea area, Direction dir)
    {
        
        PositionArea spawnPos = new PositionArea(area);
        //The first spawnpoint's position is determined by the lane's direction
        switch(dir)
        {
            case NORTH:
                //If north the first spawnpoint's anchor is Lane Length - Overtake Distance in the y direction
                spawnPos.y += Settings.LANE_LENGTH - Settings.VEHICLE_OVERTAKE_DISTANCE;
                break;
            case SOUTH:
                //The anchor is -vehicle length from the road's starting point
                spawnPos.y -= Settings.VEHICLE_MAX_LENGTH;
                break;
            case EAST:
                spawnPos.x -= Settings.VEHICLE_MAX_LENGTH;
                break;
            case WEST:
                //The anchor is Lane Length - Overtake Distance in the x direction
                spawnPos.x += Settings.LANE_LENGTH - Settings.VEHICLE_OVERTAKE_DISTANCE;
                break;
        }
        //Now we set up the sizes for each spawn point and actually create them
        switch(dir)
        {
            case NORTH:
            case SOUTH:
                //The length is max vehicle length + overtake distance
                spawnPos.yLength = Settings.VEHICLE_MAX_LENGTH + Settings.VEHICLE_OVERTAKE_DISTANCE;
                //Width is lane width
                spawnPos.xLength = Settings.LANE_WIDTH;

                //Create the necessary spawn points
                for (int i = 0; i < area.xLength; i += Settings.LANE_WIDTH)
                {
                    //Create the new spawnPoint
                    v.addSpawn(new SpawnPoint(spawnPos, dir, Settings.northSouthSpeed));
                    //Offset the spawn position for the next spawn
                    spawnPos = new PositionArea(spawnPos);
                    spawnPos.x += Settings.LANE_WIDTH;
                }
                break;
            case EAST:
            case WEST:
                spawnPos.xLength = Settings.VEHICLE_MAX_LENGTH + Settings.VEHICLE_OVERTAKE_DISTANCE;
                spawnPos.yLength = Settings.LANE_WIDTH;

                //Create the necessary spawn points
                for (int i = 0; i < area.yLength; i += Settings.LANE_WIDTH)
                {
                    //Create the new spawnPoint
                    v.addSpawn(new SpawnPoint(spawnPos, dir, Settings.eastWestSpeed));
                    //Offset the spawn position for the next spawn
                    spawnPos = new PositionArea(spawnPos);
                    spawnPos.y += Settings.LANE_WIDTH;
                }
        }
    }

    private void setupRoads()
    {
        //Block out NorthWest corner area
        PositionArea newArea = new PositionArea(0,0,Settings.LANE_LENGTH, Settings.LANE_LENGTH);
        Zone newZone = new Zone(newArea, ZoneType.BLOCKAGE);
        zones.addZone(newZone);

        //Northbound Exit Lanes
        //Setup the zone
        newArea = new PositionArea(Settings.LANE_LENGTH, 0, Settings.LANE_WIDTH * Settings.northLanes, Settings.LANE_LENGTH);
        newZone = new Zone(newArea, ZoneType.ROAD);
        zones.addZone(newZone);

        //Southbound Turning Lane
        newArea = new PositionArea(newArea);
        newArea.x += Settings.northLanes * Settings.LANE_WIDTH;
        newArea.xLength = Settings.LANE_WIDTH;
        newZone = new Zone(newArea, ZoneType.TURN_LANE);
        zones.addZone(newZone);

        //Southbound Approach Lanes
        newArea = new PositionArea(newArea);
        newArea.x += Settings.LANE_WIDTH;
        newArea.xLength = Settings.southLanes * Settings.LANE_WIDTH;
        newZone = new Zone(newArea, ZoneType.ROAD);
        zones.addZone(newZone);
        //Create spawns for southbound approach
        createSpawns(newArea, Direction.SOUTH);

        //NorthEast corner block
        newArea = new PositionArea(newArea);
        newArea.x += Settings.southLanes * Settings.LANE_WIDTH;
        newArea.xLength = Settings.LANE_LENGTH;
        newZone = new Zone(newArea, ZoneType.BLOCKAGE);
        zones.addZone(newZone);

        //Northbound Approach Lane
        newArea = new PositionArea(Settings.LANE_LENGTH, Settings.LANE_LENGTH + (Settings.eastLanes + Settings.westLanes + 1) * Settings.LANE_WIDTH,
                Settings.LANE_WIDTH * Settings.northLanes, Settings.LANE_LENGTH);
        newZone = new Zone(newArea, ZoneType.ROAD);
        zones.addZone(newZone);
        createSpawns(newArea, Direction.NORTH);

        //Northbound Turning Lane
        newArea = new PositionArea(newArea);
        newArea.x += Settings.northLanes * Settings.LANE_WIDTH;
        newArea.xLength = Settings.LANE_WIDTH;
        newZone = new Zone(newArea, ZoneType.TURN_LANE);
        zones.addZone(newZone);

        //Southbound Exit Lane
        newArea = new PositionArea(newArea);
        newArea.x += Settings.LANE_WIDTH;
        newArea.xLength = Settings.southLanes * Settings.LANE_WIDTH;
        newZone = new Zone(newArea, ZoneType.ROAD);
        zones.addZone(newZone);

        //Eastbound Approach
        newArea = new PositionArea(0,Settings.LANE_LENGTH, Settings.LANE_LENGTH, Settings.eastLanes * Settings.LANE_WIDTH);
        newZone = new Zone(newArea, ZoneType.ROAD);
        zones.addZone(newZone);
        createSpawns(newArea, Direction.EAST);

        //Eastbound Turning
        newArea = new PositionArea(newArea);
        newArea.y += Settings.eastLanes * Settings.LANE_WIDTH;
        newArea.yLength = Settings.LANE_WIDTH;
        newZone = new Zone(newArea, ZoneType.TURN_LANE);
        zones.addZone(newZone);

        //Westbound Exit
        newArea = new PositionArea(newArea);
        newArea.y += Settings.LANE_WIDTH;
        newArea.yLength = Settings.westLanes * Settings.LANE_WIDTH;
        newZone = new Zone(newArea, ZoneType.ROAD);
        zones.addZone(newZone);

        //SouthWest corner block
        newArea = new PositionArea(newArea);
        newArea.y += Settings.westLanes * Settings.LANE_WIDTH;
        newArea.yLength = Settings.LANE_LENGTH;
        newZone = new Zone(newArea, ZoneType.BLOCKAGE);
        zones.addZone(newZone);

        //Eastbound Exit
        newArea = new PositionArea(Settings.LANE_LENGTH + (Settings.northLanes + Settings.southLanes + 1) * Settings.LANE_WIDTH, Settings.LANE_LENGTH,
                Settings.LANE_LENGTH, Settings.eastLanes * Settings.LANE_WIDTH);
        newZone = new Zone(newArea, ZoneType.ROAD);
        zones.addZone(newZone);

        //Westbound turning
        newArea = new PositionArea(newArea);
        newArea.y += Settings.eastLanes * Settings.LANE_WIDTH;
        newArea.yLength = Settings.LANE_WIDTH;
        newZone = new Zone(newArea, ZoneType.TURN_LANE);
        zones.addZone(newZone);

        //Westbound approach
        newArea = new PositionArea(newArea);
        newArea.y += Settings.LANE_WIDTH;
        newArea.yLength = Settings.westLanes * Settings.LANE_WIDTH;
        newZone = new Zone (newArea, ZoneType.ROAD);
        createSpawns(newArea, Direction.WEST);
        zones.addZone(newZone);

        //SouthEast block
        newArea = new PositionArea(newArea);
        newArea.y += Settings.westLanes * Settings.LANE_WIDTH;
        newArea.yLength = Settings.LANE_LENGTH;
        newZone = new Zone (newArea, ZoneType.BLOCKAGE);
        zones.addZone(newZone);

        //Intersection area
        newArea = new PositionArea(Settings.LANE_LENGTH, Settings.LANE_LENGTH,
                (Settings.northLanes + Settings.southLanes + 1) * Settings.LANE_WIDTH,
                (Settings.eastLanes + Settings.westLanes + 1) * Settings.LANE_WIDTH);
        newZone = new Zone(newArea, ZoneType.INTERSECTION);
        zones.addZone(newZone);
    }

    public View getView()
    {
        return new View(v.vehicles, zones.getAreas(), tl.getLightStates());
    }
}
